

/**
 *
 * Ori Weisler  ID 060512878
 * Roni Lahav   ID 043489889 
 * Date: Apr 15, 2009
 */

import java.io.*;
import java.util.ArrayList;


public class Lexer
{
	final int main=1000, times=1, div=3, struct=1003, int_=1002, eql=9, minus=7, plus=6, cin=1005, cout=1007,
	out=1008, in_=1006, dot=18, comma=19, rparen=22, lparen=29, rbrak=23, lbrak=30,
	number=34, ident=37, semicolon=38, const_=57, lblock=1001, rblock=1004, error=666,
	enter=25, space=25, EOF_=64;

	public char ch;
	public int sym, lastNumber;
	public String lastIdent;
	public BufferedReader in;
    private char[] buffer;
    private int index=0;
    private ArrayList<String> tokens = new ArrayList<String>();


    /**
     * Used for printing - convert int symbol to sign for printing
     * @param symbol
     * @return
     */
     public String toString(int symbol){
        switch(symbol){
            case main:
                return "main()";
             case times:
                return "*";
            case plus:
                return "+";
            case minus:
                return "-";
            case eql:
                return "=";
            case out:
                return "<<";
            case in_:
                return ">>";
            case semicolon:
                return ";";
            case comma:
                return ",";
            case dot:
                return ".";
            case lparen:
                return "(";
            case rparen:
                return ")";
            case lbrak:
                return "[";
            case rbrak:
                return "]";
            case lblock:
                return "{";
            case rblock:
                return "}";
            case div:
                return "/";
            case int_:
                return "int";
            default:
                return "";
        }
    }

    /**
     * return char according to index. We are using a buffer for each row, but
     * for oomfortability, working with one char only each time
     * @return
     */
    private char getNextChar() {
        char c;
        if( index < buffer.length ){
            c = buffer[index];
            index++;
            return c;
        }
        else{
            return (char)-1;
        }

    }
    //initialize the input variable and read one char
	public Lexer(String stream){
        buffer = stream.toCharArray();
        ch = this.getNextChar();
	}

    private ArrayList<String> getTokens() {
        return this.tokens;
    }

    //return one token
	public int get(){
		String buffer;
		while (true){
			try{
				 if ((ch >= 'A' && ch <= 'Z') || (ch >= 'a' && ch <= 'z')){
					buffer = new String(ch + "");
					do{
						ch = this.getNextChar();//char) in.read();
						if((ch >= 'A' && ch <= 'Z') || (ch >= 'a' && ch <= 'z') || (ch >= '0' && ch <= '9'))
							buffer = buffer + ch;
					} while ((ch >= 'A' && ch <= 'Z') || (ch >= 'a' && ch <= 'z') || (ch >= '0' && ch <= '9'));
                    tokens.add( buffer );
                    if (buffer.equals("main"))
					{
						return main;
					}
					if (buffer.equals("struct"))
					{
						return struct;
					}
					if (buffer.equals("cin"))
					{
						return cin;
					}
					if (buffer.equals("cout"))
					{
						return cout;
					}
					if (buffer.equals("int"))
					{
						return int_;
					}
					lastIdent = new String(buffer);  //save the last ident
					return ident;
				}
				else{
					if (ch >= '0' && ch <= '9')
					{
						buffer = new String(ch + "");
						do
						{
							ch = this.getNextChar();//char) in.read();
							if (ch >= '0' && ch <= '9')
								buffer = buffer + ch;
						} while (ch >= '0' && ch <= '9');
						if ((ch >= 'A' && ch <= 'Z') || (ch >= 'a' && ch <= 'z'))
						{
							buffer = buffer + ch;
							do
							{
								ch = this.getNextChar();//char) in.read();
								if ((ch >= 'A' && ch <= 'Z') || (ch >= 'a' && ch <= 'z') || (ch >= '0' && ch <= '9'))
									buffer = buffer + ch;
							} while ((ch >= 'A' && ch <= 'Z') || (ch >= 'a' && ch <= 'z') || (ch >= '0' && ch <= '9'));
							return error;
						}
                        tokens.add( buffer );
                        lastNumber = Integer.parseInt(buffer);  //save the last number
						return number;
					}
					else
					{
						if((byte)ch == -1)
						{
							return EOF_;
						}
                        int returnVal;
                        boolean ioflag = false;
                        switch (ch)
						{
							case '*':
                                returnVal = times;
                                break;
                            case '+':
                                returnVal = plus;
                                break;
                            case '-':
                                returnVal = minus;
                                break;
                            case '=':
                                returnVal = eql;
                                break;
                            case '<':
                                if (ch == '<')
								{
                                    ioflag = true;
                                    returnVal = out;
                                }
                                else
                                {
                                    returnVal = error;
                                }
                                break;
                            case '>':
                                if (ch == '>')
                                {
                                    ioflag = true;
                                    returnVal = in_;
                                }
                                else
                                {
                                    returnVal = error;
                                }
                                break;
                            case ';':
                                returnVal = semicolon;
                                break;
                            case ',':
                                returnVal = comma;
                                break;
                            case '.':
                                returnVal = dot;
                                break;
                            case '(':
                                returnVal = lparen;
                                break;
                            case ')':
                                returnVal = rparen;
                                break;
                            case '[':
                                returnVal = lbrak;
                                break;
                            case ']':
                                returnVal = rbrak;
                                break;
                            case '{':
                                returnVal = lblock;
                                break;
                            case '}':
                                returnVal = rblock;
                                break;
                            case '/':
                                returnVal = div;
                                break;
                            case '\t':
							case ' ':
							case '\n':
							case '\r':
                                ch = this.getNextChar();
                                continue;
							default:
                                returnVal = error;
                                break;
                        }
                        ch = this.getNextChar();
                        if ( ioflag == true ){
                            if( ch == '<')
                                returnVal = out;
                            if( ch == '>' )
                                returnVal = in_;
                            ch = this.getNextChar();
                        }
                        tokens.add( this.toString(returnVal) );
                        return returnVal;
                    }
                 }
            }
			catch (Exception e)
			{
                if( ch != -1)
                    return ch;
                else{
                    ch = (char) -1;
                    return -1;
                }
                
			}
        }
    }

    public static void main(String[] args)
	{
		 int sym = 1;

		String filename = "input.txt";
        try {
            BufferedReader in = new BufferedReader(new FileReader( filename ));
            ArrayList<String> tokens = null, patterns;
            String line = null;
            boolean isEndOfFile = false;
            while ( (line = in.readLine()) != null){
                if( ! line.equals("")){
                    System.out.println();
                    tokens = new ArrayList<String>();
                    System.out.println( line ); //printing line
                    Lexer lexer = new Lexer( line );
                    for( int i=0; i<line.length() && !isEndOfFile;i++){
                        sym = lexer.get();
                        if( sym != 64 )
                            tokens.add( Integer.toString(sym) );
                        else
                            isEndOfFile=true;
                    }
                    isEndOfFile = false;
                    patterns = lexer.getTokens();
                    for(int i=0; i< patterns.size();i++){
                        System.out.print( patterns.get(i) +     "\t");
                    }
                    System.out.println();
                    for(int i=0; i< tokens.size();i++){
                        System.out.print(  tokens.get(i) + "\t");
                    }
                    System.out.println();
                }
            }
        } catch ( Exception e ) {
            e.printStackTrace();  //To change body of catch statement use File | Settings | File Templates.
        }

	}
}




